【Unity】VRでGrabTextureを利用する

October 26, 2022


VR開発において360°動画を描画させた後、その動画に対して一部分を歪ませるエフェクトを実装しようと思いました

URPで合ってもHaruma-Kさんが公開されている URPGrabPass https://github.com/Haruma-K/URPGrabPass

を利用すればカメラが描画した後のテクスチャを取得してShaderで加工してエフェクトを乗せることが出来ます。

_CameraOpaqueTexture 利用時と違い、半透明描画後のカラーテクスチャも利用できるのが最高に良い..

VR利用時の問題

しかし、上記のGrabTexture利用時Oculus Quest2でシミュレートした時画面が正常に映らない問題が出ました。 正確には左半分がグレイカラーとなり右半分が真っ黒。

これでは使いものになリませんでしたが RenderModeを SinglePath-Instancedではなく、Multi-pass 方式にすると上記現象が発生せず問題ありません。

「Multi-passでも良いか..」とも思いましたが、せっかくのパフォーマンス最適化を犠牲にするため調査したところUnity2022にすると問題ないことがわかりました。

それはUnityForumで報告されていますが Unity2021まではXR上でBlitは利用してはいけませんでした https://forum.unity.com/threads/documentation-and-or-a-unity-blog-post-on-how-to-blit-in-urp-and-what-every-blit-function-does.1211508/#post-7735527

Blitに関して

  • 将来Blitはなくなるかも
  • BlitはXRでは動かない

とのことで。 Blit利用時に何か動かしている結果XRのSinglePath-Instancedの利用ができなくなっているようです

解決方法

Unity2022からはScriptableRenderPass内で利用する Blit メソッドが非推奨扱いになり、代わりに Blitter.BlitCameraTexture を利用します 引数は RenderTargetIdentifier ではなく、 RTHandle を受け取ります。

Blit時の処理を以下に変更しました

// 2022~
Blitter.BlitCameraTexture(cmd, _renderer.cameraColorTargetHandle, _grabbedTextureHandle);

// original
//Blit(cmd, _renderer.cameraColorTarget, _grabbedTextureHandle.nameID);

Executeメソッド内のBlit処理を ScriptableRenderer の cameraColorTargetHandle を利用 ScriptableRenderer は ScriptableRendererFeature 側から適当なメソッドで渡してあげています。もしくは直接RTHandleを渡す。

この状態であればシングルパスインスタンシングでも描画が問題ありません。

シェーダー内で以下の形でテクスチャを受け取り

// VR用
TEXTURE2D_X(_GrabbedTexture);  // 内部でSinglePass-instancing利用時にはテクスチャアレイになる
SAMPLER(sampler_GrabbedTexture);

テクスチャ参照するときは以下のような形

half4 frag(Varyings IN) : SV_Target
{
    UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(IN);

   // float3のZ要素に「左右のどちらを描画するか」を判別するIndexを指定する。 0(左) or 1(右)
    return _GrabbedTexture.Sample(sampler_GrabbedTexture, float3(IN.samplingViewportPos, SLICE_ARRAY_INDEX));
}

SLICE_ARRAY_INDEX が左、右どちらかの値(0 or 1)が入っています。 (SInglePass-instancing利用時は必ず0)